import Vue from 'vue'
import router from './link'
import { getToken, setToken, removeToken } from '@/utils/user'
import { getEnv } from '@/utils/buffer'
import { ERR_CODE, TOKEN_ERR } from '@/static/errCode'
import { getCurrentScheme } from '@/utils/scheme'
let token

/**
 * 请求开始，
 */
function startRequest(config) {
  /* 设置全局请求参数 */
  Vue.prototype.$storeCommit('setLoading', true)
  Vue.prototype.$storeCommit('addRequestingNum')
  token = getToken()
  /* 拼接请求头 */
  const headers = {
    'Content-Type': 'application/json; charset=utf-8',
    'Authorization': token,
    ...config.headers
  }

  delete config.headers

  return headers
}

/**
 * 检验token
 */
function checkToken(res) {
  if (res.header.Authorization) {
    console.log('新token', res.header.Authorization)
    setToken(res.header.Authorization)
  }
  return res.data
}

/**
 * 响应数据检查
 */
function checkResponse(res) {
  return res.data
}

/**
 * 错误响应
 */
function responseErr(err, url, method, data, config = {}) {
  console.log('======请求错误', err)
  if (err.errMsg === 'request:fail timeout') {
    Vue.prototype.$error('请求超时')
  } else if (err.code) {
    /* 鉴权失败 */
    if (TOKEN_ERR[ err.code ]) {
      /* 没有token 或者 token跟本地值相同，说明没有被重置过，是真正的过期 */
      if (!getToken() || token === getToken()) {
        removeToken()
        if (config.hold === true) { // token过期，但如果有hold字段，也不会报错
          return Promise.resolve(err)
        } else { // 保存当前页面scheme，登录后回滚
          router.redirectToLogin({ scheme: getCurrentScheme() }, () => {
            Vue.prototype.$msg('请先登录')
          })
        }
      } else {
        return myRequest(url, method, data, config)
      }
    } else {
      Vue.prototype.$error(err.msg || ERR_CODE[ err.code ] || '请求错误')
    }
  } else if (err.statusCode) {
    Vue.prototype.$error(ERR_CODE[ err.statusCode ] || '请求错误')
  } else {
    Vue.prototype.$error('请求错误')
  }
  return Promise.reject(err)
}

/**
 * 请求结束
 */
function requestEnd() {
  /* 请求中数量-1 */
  Vue.prototype.$storeCommit('subRequestingNum')
  /* 如果请求数量等于0，关闭loading */
  if (Vue.prototype.$getState('requestStore', 'requestingNum') <= 0) {
    Vue.prototype.$storeCommit('setLoading', false)
  }
}

function myRequest(url, method, data, config = {}) {
  /* 配置请求头 */
  const headers = startRequest(config)
  const path = getEnv().baseUrl + '/api' + url

  for (const key in data) {
    if (data[ key ] === undefined) {
      delete data[ key ]
    }
  }

  return new Promise((resolve, reject) => {
    uni.request({
      url: path,
      method: method,
      data: data,
      header: headers,
      timeout: 10000,
      ...config,
      success(res) {
        if (!res.data) {
          Vue.prototype.$error('响应数据为空')
          reject({})
        } else if (res.data.code >= 300 || res.data.code < 200) { // 有响应错误先走响应错误
          reject(res.data)
        } else if (res.statusCode >= 300 || res.statusCode < 200) { // 无响应错误走默认错误
          reject(res)
        } else {
          resolve(res)
        }
      },
      fail(err) {
        reject(err)
      },
      complete(res) {
        /* 手机端，打印数据 */
        if (uni.getSystemInfoSync().platform !== 'devtools') {
          console.log(`request==>${ method }`, path, res.data.data)
        }
      }
    })
  })
    .then(checkToken)
    .then(checkResponse)
    .catch((err) => responseErr(err, url, method, data, config))
    .finally(requestEnd)
}
export default myRequest
